<template>
  <div class="stream-output">
    <a-card title="AI 流式对话" class="stream-card">
      <!-- 输入区域 -->
      <div class="input-section">
        <a-textarea
          v-model:value="inputText"
          placeholder="请输入您的问题..."
          :rows="3"
          :disabled="isStreaming"
          class="input-textarea"
          @keydown.ctrl.enter="handleSubmit"
        />
        <div class="input-actions">
          <a-button
            type="primary"
            :loading="isStreaming"
            :disabled="!inputText.trim()"
            @click="handleSubmit"
            class="submit-button"
          >
            <template #icon>
              <Send v-if="!isStreaming" :size="16" />
              <Square v-else :size="16" />
            </template>
            {{ isStreaming ? '停止生成' : '发送' }}
          </a-button>
          <a-button @click="clearOutput" :disabled="isStreaming">
            <template #icon>
              <Trash2 :size="16" />
            </template>
            清空
          </a-button>
        </div>
      </div>

      <!-- 输出区域 -->
      <div class="output-section" v-if="outputText || isStreaming">
        <a-divider>AI 回复</a-divider>
        <div class="output-container">
          <div class="output-content">
            <div class="message-bubble user-message" v-if="lastUserInput">
              <div class="message-header">
                <User :size="16" />
                <span>用户</span>
              </div>
              <div class="message-text">{{ lastUserInput }}</div>
            </div>

            <div class="message-bubble ai-message">
              <div class="message-header">
                <Bot :size="16" />
                <span>AI 助手</span>
              </div>
              <div class="message-text">
                <span v-html="formattedOutput"></span>
                <span v-if="isStreaming" class="cursor">|</span>
              </div>
            </div>
          </div>

          <!-- 流式状态指示器 -->
          <div class="streaming-indicator" v-if="isStreaming">
            <div class="dots">
              <span></span>
              <span></span>
              <span></span>
            </div>
            <span class="status-text">AI 正在思考中...</span>
          </div>
        </div>
      </div>

      <!-- 统计信息 -->
      <div class="stats-section" v-if="outputText">
        <a-row :gutter="16">
          <a-col :span="8">
            <a-statistic title="输出字数" :value="outputText.length" />
          </a-col>
          <a-col :span="8">
            <a-statistic title="生成时间" :value="generationTime" suffix="秒" :precision="1" />
          </a-col>
          <a-col :span="8">
            <a-statistic title="生成速度" :value="generationSpeed" suffix="字/秒" :precision="1" />
          </a-col>
        </a-row>
      </div>
    </a-card>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, nextTick, onUnmounted } from 'vue'
import { message } from 'ant-design-vue'
import { Send, Square, Trash2, User, Bot } from 'lucide-vue-next'
import { useAuthStore } from '@/stores'

interface Props {
  wsUrl?: string // WebSocket地址
  streamDelay?: number // 流式输出延迟（毫秒）
  maxLength?: number // 最大输出长度
  enableMockData?: boolean // 是否启用模拟数据
}

interface Emits {
  submit: [input: string]
  streamStart: []
  streamEnd: [output: string]
  error: [error: string]
}

const props = withDefaults(defineProps<Props>(), {
  wsUrl: 'wss://www.codewin.top/codewin/ai/chat/qwen-stream',
  streamDelay: 50,
  maxLength: 2000,
  enableMockData: false
})

const emit = defineEmits<Emits>()

// 初始化认证store
const authStore = useAuthStore()

// 响应式数据
const inputText = ref('')
const outputText = ref('')
const lastUserInput = ref('')
const isStreaming = ref(false)
const generationTime = ref(0)
const generationSpeed = ref(0)

// 流式输出相关
let streamTimer: number | null = null
let startTime: number = 0
let streamEndTimer: number | null = null // 用于检测流式输出结束的定时器

// 模拟数据
const mockResponses = [
  "您好！我是AI助手，很高兴为您服务。我可以帮助您解答各种问题，包括技术咨询、学习指导、创意写作等。请告诉我您需要什么帮助？",
  "这是一个很有趣的问题！让我来详细分析一下：\n\n1. 首先，我们需要理解问题的核心\n2. 然后分析可能的解决方案\n3. 最后提供具体的建议\n\n基于以上分析，我建议您可以从以下几个方面入手...",
  "关于Vue 3的组合式API，它确实是一个非常强大的特性。相比于选项式API，组合式API提供了更好的逻辑复用性和类型推导支持。\n\n主要优势包括：\n- 更好的TypeScript支持\n- 逻辑组合更灵活\n- 代码组织更清晰\n- 性能优化更容易",
  "人工智能技术正在快速发展，从机器学习到深度学习，再到现在的大语言模型，每一次技术革新都带来了新的可能性。未来的AI将更加智能化、个性化，能够更好地理解和服务人类的需求。"
]

// 格式化输出文本（支持换行）
const formattedOutput = computed(() => {
  return outputText.value.replace(/\n/g, '<br>')
})

// 获取随机模拟响应
const getRandomMockResponse = () => {
  return mockResponses[Math.floor(Math.random() * mockResponses.length)]
}

// 流式输出函数
const streamText = (text: string) => {
  return new Promise<void>((resolve) => {
    let index = 0
    outputText.value = ''
    startTime = Date.now()

    const stream = () => {
      if (index < text.length && isStreaming.value) {
        outputText.value += text[index]
        index++

        // 更新统计信息
        const elapsed = (Date.now() - startTime) / 1000
        generationTime.value = elapsed
        generationSpeed.value = elapsed > 0 ? outputText.value.length / elapsed : 0

        streamTimer = window.setTimeout(stream, props.streamDelay)
      } else {
        isStreaming.value = false
        const finalTime = (Date.now() - startTime) / 1000
        generationTime.value = finalTime
        generationSpeed.value = finalTime > 0 ? outputText.value.length / finalTime : 0
        emit('streamEnd', outputText.value)
        resolve()
      }
    }

    stream()
  })
}

// WebSocket连接和流式处理
let websocket: WebSocket | null = null

// 创建WebSocket连接
const createWebSocketConnection = (): Promise<WebSocket> => {
  return new Promise((resolve, reject) => {
    // 添加token鉴权到WebSocket URL
    const token = authStore.token
    const wsUrl = `wss://www.codewin.top/codewin/ai/chat/qwen-stream?token=${encodeURIComponent(token || '')}`
    const ws = new WebSocket(wsUrl)

    ws.onopen = () => {
      console.log('WebSocket连接已建立')
      resolve(ws)
    }

    ws.onerror = (error) => {
      console.error('WebSocket连接错误:', error)
      reject(new Error('WebSocket连接失败'))
    }

    ws.onclose = () => {
      console.log('WebSocket连接已关闭')
      websocket = null

      // 如果连接关闭时还在流式输出状态，自动结束
      if (isStreaming.value) {
        isStreaming.value = false
        const finalTime = (Date.now() - startTime) / 1000
        generationTime.value = finalTime
        generationSpeed.value = finalTime > 0 ? outputText.value.length / finalTime : 0
        emit('streamEnd', outputText.value)

        // 清理定时器
        if (streamEndTimer) {
          clearTimeout(streamEndTimer)
          streamEndTimer = null
        }
      }
    }
  })
}

// 通过WebSocket发送消息并处理流式响应
const callStreamAPI = async (input: string): Promise<void> => {
  if (props.enableMockData) {
    // 使用模拟数据
    await new Promise(resolve => setTimeout(resolve, 500)) // 模拟网络延迟
    const response = getRandomMockResponse() as string
    await streamText(response)
    return
  }

  try {
    // 创建WebSocket连接
    if (!websocket || websocket.readyState !== WebSocket.OPEN) {
      websocket = await createWebSocketConnection()
    }

    // 设置消息处理器
    websocket.onmessage = (event) => {
      try {
        // 清除之前的结束检测定时器
        if (streamEndTimer) {
          clearTimeout(streamEndTimer)
          streamEndTimer = null
        }

        // 尝试解析JSON格式的消息
        let data
        try {
          data = JSON.parse(event.data)
        } catch (jsonError) {
          // 如果不是JSON格式，直接作为文本流处理
          const textContent = event.data
          if (textContent && textContent.trim() && isStreaming.value) {
            // 实时追加文本内容
            outputText.value += textContent

            // 更新统计信息
            const elapsed = (Date.now() - startTime) / 1000
            generationTime.value = elapsed
            generationSpeed.value = elapsed > 0 ? outputText.value.length / elapsed : 0

            // 设置结束检测定时器（1秒内没有新数据则认为结束）
            streamEndTimer = window.setTimeout(() => {
              if (isStreaming.value) {
                isStreaming.value = false
                const finalTime = (Date.now() - startTime) / 1000
                generationTime.value = finalTime
                generationSpeed.value = finalTime > 0 ? outputText.value.length / finalTime : 0
                emit('streamEnd', outputText.value)
              }
            }, 1000)
          } else if (!textContent || !textContent.trim()) {
            // 如果是空消息，可能是服务器的结束信号，直接结束流式输出
            if (isStreaming.value && outputText.value.length > 0) {
              isStreaming.value = false
              const finalTime = (Date.now() - startTime) / 1000
              generationTime.value = finalTime
              generationSpeed.value = finalTime > 0 ? outputText.value.length / finalTime : 0
              emit('streamEnd', outputText.value)
            }
          }
          return
        }

        // 处理JSON格式的消息
        if (data.type === 'chunk' && data.content) {
          // 实时追加内容
          outputText.value += data.content

          // 更新统计信息
          const elapsed = (Date.now() - startTime) / 1000
          generationTime.value = elapsed
          generationSpeed.value = elapsed > 0 ? outputText.value.length / elapsed : 0
        } else if (data.type === 'end') {
          // 流式输出结束
          isStreaming.value = false
          const finalTime = (Date.now() - startTime) / 1000
          generationTime.value = finalTime
          generationSpeed.value = finalTime > 0 ? outputText.value.length / finalTime : 0
          emit('streamEnd', outputText.value)
        } else if (data.type === 'error') {
          // 处理错误
          throw new Error(data.message || '服务器返回错误')
        }
      } catch (error) {
        console.error('处理WebSocket消息失败:', error)
        isStreaming.value = false
        emit('error', '处理响应数据失败')
      }
    }

    // 发送消息
    const message = {
      type: 'chat',
      content: input,
      max_tokens: props.maxLength
    }

    websocket.send(JSON.stringify(message))

  } catch (error) {
    console.error('WebSocket通信失败:', error)
    throw error
  }
}

// 提交处理
const handleSubmit = async () => {
  if (!inputText.value.trim() || isStreaming.value) return

  const input = inputText.value.trim()
  lastUserInput.value = input
  emit('submit', input)

  try {
    isStreaming.value = true
    emit('streamStart')

    // 清空之前的输出
    outputText.value = ''
    generationTime.value = 0
    generationSpeed.value = 0
    startTime = Date.now()

    // 通过WebSocket发送消息
    await callStreamAPI(input)

    // 清空输入框
    inputText.value = ''

  } catch (error) {
    isStreaming.value = false
    const errorMsg = error instanceof Error ? error.message : '请求失败'
    emit('error', errorMsg)
    message.error(errorMsg)
  }
}

// 停止生成
const stopGeneration = () => {
  if (streamTimer) {
    clearTimeout(streamTimer)
    streamTimer = null
  }

  if (streamEndTimer) {
    clearTimeout(streamEndTimer)
    streamEndTimer = null
  }

  // 发送停止信号到WebSocket
  if (websocket && websocket.readyState === WebSocket.OPEN) {
    websocket.send(JSON.stringify({ type: 'stop' }))
  }

  isStreaming.value = false
  emit('streamEnd', outputText.value)
}

// 清空输出
const clearOutput = () => {
  if (isStreaming.value) {
    stopGeneration()
  }
  outputText.value = ''
  lastUserInput.value = ''
  generationTime.value = 0
  generationSpeed.value = 0
}

// 组件卸载时关闭WebSocket连接
onUnmounted(() => {
  if (streamTimer) {
    clearTimeout(streamTimer)
    streamTimer = null
  }

  if (streamEndTimer) {
    clearTimeout(streamEndTimer)
    streamEndTimer = null
  }

  if (websocket) {
    websocket.close()
    websocket = null
  }
})

// 暴露方法给父组件
defineExpose({
  submit: handleSubmit,
  stop: stopGeneration,
  clear: clearOutput,
  isStreaming: computed(() => isStreaming.value),
  outputText: computed(() => outputText.value)
})
</script>

<style scoped>
.stream-output {
  width: 100%;
  max-width: 800px;
  margin: 0 auto;
}

.stream-card {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}

.input-section {
  margin-bottom: 1.5rem;
}

.input-textarea {
  margin-bottom: 1rem;
  border-radius: 8px;
  border: 2px solid #e0e7ff;
  transition: border-color 0.3s ease;
}

.input-textarea:focus {
  border-color: #60a5fa;
  box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.1);
}

.input-actions {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
}

.submit-button {
  background: linear-gradient(135deg, #60a5fa 0%, #3b82f6 100%);
  border: none;
  box-shadow: 0 2px 8px rgba(96, 165, 250, 0.3);
}

.submit-button:hover {
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
  box-shadow: 0 4px 12px rgba(96, 165, 250, 0.4);
}

.output-section {
  margin-top: 1.5rem;
}

.output-container {
  background: #f8fafc;
  border-radius: 12px;
  padding: 1.5rem;
  min-height: 200px;
  width: 100%;
}

.output-content {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  width: 100%;
}

.message-bubble {
  padding: 1rem;
  border-radius: 12px;
  width: 100%;
  box-sizing: border-box;
}

.user-message {
  background: linear-gradient(135deg, #e0e7ff 0%, #c7d2fe 100%);
  border: 1px solid #a5b4fc;
}

.ai-message {
  background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
  border: 1px solid #7dd3fc;
}

.message-header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.5rem;
  font-weight: 600;
  font-size: 0.9rem;
  color: #4b5563;
}

.message-text {
  line-height: 1.6;
  color: #1f2937;
  text-align: left;
  word-wrap: break-word;
  word-break: break-word;
}

.cursor {
  animation: blink 1s infinite;
  color: #60a5fa;
  font-weight: bold;
}

@keyframes blink {
  0%, 50% { opacity: 1; }
  51%, 100% { opacity: 0; }
}

.streaming-indicator {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 1rem;
  color: #6b7280;
}

.dots {
  display: flex;
  gap: 4px;
}

.dots span {
  width: 6px;
  height: 6px;
  background: #60a5fa;
  border-radius: 50%;
  animation: wave 1.4s ease-in-out infinite both;
}

.dots span:nth-child(1) { animation-delay: -0.32s; }
.dots span:nth-child(2) { animation-delay: -0.16s; }
.dots span:nth-child(3) { animation-delay: 0s; }

@keyframes wave {
  0%, 80%, 100% {
    transform: scale(0);
    opacity: 0.5;
  }
  40% {
    transform: scale(1);
    opacity: 1;
  }
}

.stats-section {
  margin-top: 1.5rem;
  padding: 1rem;
  background: #f1f5f9;
  border-radius: 8px;
}

/* 响应式设计 */
@media (max-width: 768px) {
  .stream-output {
    max-width: 100%;
    padding: 0 1rem;
  }

  .message-bubble {
    max-width: 95%;
  }

  .input-actions {
    flex-direction: column;
  }

  .input-actions .ant-btn {
    width: 100%;
  }
}
</style>
